/* Copyright (C) 2012  Chris Mueller <ruunsmail@googlemail.com>
 *
 * This file is part of the Liquid Programming Language
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "parser.h"
#include "nodes.h"
#include "symbol.h"
#include "context.h"
#include "map.h"
#include <assert.h>
#include <string.h>
#include <stdlib.h>


struct LqNode*  
lq_parse(struct LqContext* context)
{
	assert(context != 0);

	struct LqNode* root = lq_node_new(0, LQ_NODE_ROOT, 0);

        lq_parse_enter_scope(context, root);

	while(!lq_parse_is_next(context, LQ_TOKEN_EOF, 0)) {
		struct LqNode* toplevel = lq_parse_toplevel(context);
		lq_node_append(root, toplevel);
	}

        lq_parse_leave_scope(context);

	lq_parse_eat(context, LQ_TOKEN_EOF, "Missing END OF FILE token in this source file");

	context->ast_root = root;	
	return root;
}


struct LqToken
lq_parse_next(struct LqContext* context)
{
	assert(context != 0);

	struct LqToken token;

	do {
		token = lq_scanner_next(context);
	} while(token.value == LQ_TOKEN_NEWLINE);

	return token;
}


void            
lq_parse_eat(struct LqContext* context, enum LqTOK value, const byte* error)
{
	assert(context != 0);

	struct LqToken token = lq_scanner_next(context);

	while(value != LQ_TOKEN_NEWLINE && token.value == LQ_TOKEN_NEWLINE)
		token = lq_scanner_next(context);

	if(token.value != value) {
		lq_error_at_line(context->file, token.line, "%s (wrong token %s, expected %s)", error, lq_tok_to_string(token.value), lq_tok_to_string(value));
	}
}


int		
lq_parse_is_next(struct LqContext* context, enum LqTOK value, size_t size)
{
	assert(context != 0);

	struct LqToken token;
	size_t next_lookahead = 0;

	do {
		do {
			token = lq_scanner_peek(context, next_lookahead++);
		} while(value != LQ_TOKEN_NEWLINE && token.value == LQ_TOKEN_NEWLINE);
	} while(size-- > 0);

	return token.value == value;;
}


int		
lq_parse_is_next_on_line(struct LqContext* context, enum LqTOK value)
{
	assert(context != 0);
	assert(value != LQ_TOKEN_NEWLINE);

	struct LqToken token;
	size_t next_lookahead = 0;

	do {
		token = lq_scanner_peek(context, next_lookahead++);

		if(token.value == value)
			return TRUE;

	} while(token.value != LQ_TOKEN_NEWLINE && token.value != LQ_TOKEN_EOF);

	return FALSE;
}

	
int        
lq_parse_eat_if(struct LqContext* context, enum LqTOK value)
{
	assert(context != 0);

	struct LqToken token;

	if(lq_parse_is_next(context, value, 0)) {
		do {
			token = lq_scanner_next(context);
		} while(value != LQ_TOKEN_NEWLINE && token.value == LQ_TOKEN_NEWLINE);

		return TRUE;
	}

	return FALSE;
}


void
lq_parse_enter_scope(struct LqContext* context, struct LqNode* node)
{
        assert(context != 0);
        assert(node != 0);

        node->symbols = lq_map_new(lq_cast(lq_ordering_funptr, strcmp));

        lq_stack_push(context->symbols, node->symbols);
}



void
lq_parse_leave_scope(struct LqContext* context)
{
        assert(context != 0);

        lq_stack_pop(context->symbols);
}



struct LqNode*          
lq_parse_toplevel(struct LqContext* context)
{
	assert(context != 0);

	while(lq_parse_eat_if(context, LQ_TOKEN_NEWLINE)) {}

	if(lq_parse_is_next(context, LQ_TOKEN_MODULE, 0)) {
		return lq_parse_module(context);
	} else if(lq_parse_is_next(context, LQ_TOKEN_LET, 0)) {
		return lq_parse_let_pattern_expr(context);
	} else if(lq_parse_is_next_on_line(context, '='))
		return lq_parse_assignment_pattern_expr(context);

	return lq_parse_expr(context);
}


struct LqNode*		
lq_parse_module(struct LqContext* context)
{
	assert(context != 0);

	lq_parse_eat(context, LQ_TOKEN_MODULE, "Module keyword expected in this expression");
	lq_parse_eat(context, LQ_TOKEN_IDENTIFIER, "Identifier expression not found in this module declaration");

	int line = lq_scanner_line(context);
	byte* string = lq_scanner_string(context);

	struct LqNode* module = lq_node_module_new(line,  string);
	struct LqSymbol* symbol = lq_symbol_namespace_new(line, module);

	if(lq_symboltable_add(context, string, symbol) == FALSE) {
		free(symbol);
		lq_error_at_line(context->file, line, "Conflicting module declarations. %s has alredy been set in this scope", string);
	}

	lq_parse_enter_scope(context, module);

	if(lq_parse_eat_if(context, '{')) {
		while(!lq_parse_is_next(context, '}', 0) && !lq_parse_is_next(context, LQ_TOKEN_EOF, 0)) {
			if(lq_parse_is_next(context, LQ_TOKEN_LET, 0))
				lq_node_append(module, lq_parse_let_pattern_expr(context));
		}

		lq_parse_eat(context, '}', "Module declaration misses closing '}' bracket");

	} else {
		while(!lq_parse_is_next(context, LQ_TOKEN_EOF, 0)) {
			if(lq_parse_is_next(context, LQ_TOKEN_LET, 0))
				lq_node_append(module, lq_parse_let_pattern_expr(context));
		}
	}

	lq_parse_leave_scope(context);

	return  module;
}


struct LqNode*
lq_parse_expr(struct LqContext* context)
{
	return lq_parse_logical_or_expr(context);
}


struct LqNode*
lq_parse_let_pattern_expr(struct LqContext* context)
{
        lq_parse_eat(context, LQ_TOKEN_LET, "Missing let keyword for assignment expr");
	lq_parse_eat(context, LQ_TOKEN_IDENTIFIER, "Identifier expression not found in this let declaration");

	int line = lq_scanner_line(context);
	byte* identifier = lq_scanner_string(context);
	struct LqSymbol* symbol = lq_symboltable_get(context, identifier);
	struct LqNode* let = lq_node_let_new(line, identifier);
	
	struct LqNode* node = lq_node_new(lq_scanner_line(context), '=', 2);

	if(symbol == 0) {
		lq_symboltable_add(context, identifier, lq_symbol_value_new(line, let));
	}

	lq_parse_enter_scope(context, node);

	struct LqNode* left = lq_parse_pattern_expr(context);

	lq_parse_eat(context, '=', "Functions definition expected in this source file");
	
	struct LqNode* right = lq_parse_expr(context);

	lq_node_append(node, left);
	lq_node_append(node, right);
	lq_node_append(let, node);

	lq_parse_leave_scope(context);

	lq_parse_eat_if(context, LQ_TOKEN_NEWLINE);

	return let;

}


struct LqNode*
lq_parse_assignment_pattern_expr(struct LqContext* context)
{
	struct LqNode* node = lq_node_new(lq_scanner_line(context), '=', 2);

	struct LqNode* pattern = lq_node_new(lq_scanner_line(context), LQ_NODE_PATTERN, 1);
	
	struct LqNode* left = lq_parse_cons_pattern_expr(context);

	lq_parse_eat(context, '=', "Functions definition expected in this source file");
	
	struct LqNode* right = lq_parse_expr(context);

	lq_node_append(pattern, left);
	lq_node_append(node, pattern);
	lq_node_append(node, right);

	lq_parse_eat_if(context, LQ_TOKEN_NEWLINE);

	return node;
}



struct LqNode*          
lq_parse_logical_or_expr(struct LqContext* context)
{
	assert(context != 0);

	struct LqNode* left = lq_parse_logical_and_expr(context);

	while(lq_parse_eat_if(context, LQ_TOKEN_OR)) {
		struct LqNode* node = lq_node_new(lq_scanner_line(context), LQ_NODE_OR, 2);
		struct LqNode* right = lq_parse_logical_and_expr(context);

		lq_node_append(node, left);
		lq_node_append(node, right);

		left = node;
	}

	return left;
}


struct LqNode*          
lq_parse_logical_and_expr(struct LqContext* context)
{
	assert(context != 0);

	struct LqNode* left = lq_parse_equality_expr(context);

	while(lq_parse_eat_if(context, LQ_TOKEN_AND)) {
		struct LqNode* node = lq_node_new(lq_scanner_line(context), LQ_NODE_AND, 2);
		struct LqNode* right = lq_parse_equality_expr(context);

		lq_node_append(node, left);
		lq_node_append(node, right);

		left = node;
	}

	return left;
}


struct LqNode*          
lq_parse_equality_expr(struct LqContext* context)
{
	assert(context != 0);

	struct LqNode* left = lq_parse_relational_expr(context);

	while(lq_parse_eat_if(context, LQ_TOKEN_EQUAL) || lq_parse_eat_if(context, LQ_TOKEN_NOTEQUAL)) {
		enum LqNodeKind kind = (lq_scanner_token(context) == LQ_TOKEN_EQUAL) ? LQ_NODE_EQUAL : LQ_NODE_NOTEQUAL;

		struct LqNode* node = lq_node_new(lq_scanner_line(context), kind, 2);
		struct LqNode* right = lq_parse_relational_expr(context);

		lq_node_append(node, left);
		lq_node_append(node, right);

		left = node;
	}

	return left;
}


struct LqNode*          
lq_parse_relational_expr(struct LqContext* context)
{
	assert(context != 0);

	struct LqNode* left = lq_parse_list_operation_expr(context);
	struct LqNode* right = 0;
	struct LqNode* node = 0;

	if(lq_parse_eat_if(context, LQ_TOKEN_LESS)) {
		node = lq_node_new(lq_scanner_line(context), LQ_NODE_LESS, 2);
	} else if(lq_parse_eat_if(context, LQ_TOKEN_LESSEQUAL)) {
		node = lq_node_new(lq_scanner_line(context), LQ_NODE_LESSEQUAL, 2);
	} else if(lq_parse_eat_if(context, LQ_TOKEN_GREATER)) {
		node = lq_node_new(lq_scanner_line(context), LQ_NODE_GREATER, 2);
	} else if(lq_parse_eat_if(context, LQ_TOKEN_GREATEREQUAL)) {
		node = lq_node_new(lq_scanner_line(context), LQ_NODE_GREATEREQUAL, 2);
	}

	if(node != 0) {
		right = lq_parse_list_operation_expr(context);

		lq_node_append(node, left);
		lq_node_append(node, right);

		left = node; 
	}

	return left;
}


struct LqNode*          
lq_parse_list_operation_expr(struct LqContext* context)
{
	assert(context != 0);

	struct LqNode* left = lq_parse_bitwise_or_expr(context);

	if(lq_parse_eat_if(context, LQ_TOKEN_CONCAT) || lq_parse_eat_if(context, LQ_TOKEN_REDUCE) || lq_parse_eat_if(context, LQ_TOKEN_DOUBLECOLON)) {
		enum LqNodeKind kind = 0;

		switch(lq_scanner_token(context)) {
			case LQ_TOKEN_CONCAT:
				kind = LQ_NODE_CONCAT;
				break;
			case LQ_TOKEN_REDUCE:
				kind = LQ_NODE_REDUCE;
				break;
			case LQ_TOKEN_DOUBLECOLON:
				kind = LQ_NODE_CONS;
				break;
			default:
				assert(0);
		}

		struct LqNode* node = lq_node_new(lq_scanner_line(context), kind, 2);
		struct LqNode* right = lq_parse_list_operation_expr(context);

		lq_node_append(node, left);
		lq_node_append(node, right);

		left = node;
	}

	return left;

}


struct LqNode*          
lq_parse_bitwise_or_expr(struct LqContext* context)
{
	assert(context != 0);

	struct LqNode* left = lq_parse_bitwise_xor_expr(context);

	while(lq_parse_eat_if(context, '!')) {
		struct LqNode* node = lq_node_new(lq_scanner_line(context), '!', 2);
		struct LqNode* right = lq_parse_bitwise_xor_expr(context);

		lq_node_append(node, left);
		lq_node_append(node, right);

		left = node;
	}
	
	return left;
}


struct LqNode*          
lq_parse_bitwise_xor_expr(struct LqContext* context)
{
	assert(context != 0);

	struct LqNode* left = lq_parse_bitwise_and_expr(context);

	while(lq_parse_eat_if(context, LQ_TOKEN_BXOR)) {
		struct LqNode* node = lq_node_new(lq_scanner_line(context), LQ_NODE_BXOR, 2);
		struct LqNode* right = lq_parse_bitwise_and_expr(context);

		lq_node_append(node, left);
		lq_node_append(node, right);

		left = node;
	}
	
	return left;
}


struct LqNode*          
lq_parse_bitwise_and_expr(struct LqContext* context)
{
	assert(context != 0);

	struct LqNode* left = lq_parse_shift_expr(context);

	while(lq_parse_eat_if(context, LQ_TOKEN_BAND)) {
		struct LqNode* node = lq_node_new(lq_scanner_line(context), LQ_NODE_BAND, 2);
		struct LqNode* right = lq_parse_shift_expr(context);

		lq_node_append(node, left);
		lq_node_append(node, right);

		left = node;
	}

	return left;
}


struct LqNode*          
lq_parse_shift_expr(struct LqContext* context)
{
	assert(context != 0);

	struct LqNode* left = lq_parse_additive_expr(context);

	while(lq_parse_eat_if(context, LQ_TOKEN_BITSHIFTLEFT) || lq_parse_eat_if(context, LQ_TOKEN_BITSHIFTRIGHT)) {
		enum LqNodeKind kind = (lq_scanner_token(context) == LQ_TOKEN_BITSHIFTLEFT) 
			? LQ_NODE_BITSHIFTLEFT 
			: LQ_NODE_BITSHIFTRIGHT;

		struct LqNode* node = lq_node_new(lq_scanner_line(context), kind, 2);
		struct LqNode* right = lq_parse_additive_expr(context);

		lq_node_append(node, left);
		lq_node_append(node, right);

		left = node;
	}

	return left;
}


struct LqNode*          
lq_parse_additive_expr(struct LqContext* context)
{
	assert(context != 0);

	struct LqNode* left = lq_parse_multiplicative_expr(context);

	while(lq_parse_eat_if(context, '+') || lq_parse_eat_if(context, '-')) {
		// LQ_NODE and LQ_TOKEN uses the same value for '+' and '-'
		enum LqNodeKind kind = lq_cast(enum LqNodeKind, lq_scanner_token(context)); 

		struct LqNode* node = lq_node_new(lq_scanner_line(context), kind, 2);
		struct LqNode* right = lq_parse_multiplicative_expr(context);

		lq_node_append(node, left);
		lq_node_append(node, right);

		left = node;
	}

	return left;
}


struct LqNode*          
lq_parse_multiplicative_expr(struct LqContext* context)
{
	assert(context != 0);

	struct LqNode* left = lq_parse_power_expr(context);

	while(lq_parse_eat_if(context, '*') || lq_parse_eat_if(context, '/') || lq_parse_eat_if(context, LQ_TOKEN_MODULO)) {
		enum LqNodeKind kind = 0;

		switch(lq_scanner_token(context)) {
			case '*':
			case '/':
				kind = lq_cast(enum LqNodeKind, lq_scanner_token(context));
				break;
			case LQ_TOKEN_MODULO:
				kind = LQ_NODE_MODULO;
				break;
			default:
				assert(0);
		}

		struct LqNode* node = lq_node_new(lq_scanner_line(context), kind, 2);
		struct LqNode* right = lq_parse_power_expr(context);

		lq_node_append(node, left);
		lq_node_append(node, right);

		left = node;
	}

	return left;
}


struct LqNode*          
lq_parse_power_expr(struct LqContext* context)
{
	assert(context != 0);

	struct LqNode* left = lq_parse_unary_expr(context);

	if(lq_parse_eat_if(context, '^')) {
		struct LqNode* node = lq_node_new(lq_scanner_line(context), '^', 2);
		struct LqNode* right = lq_parse_power_expr(context);

		lq_node_append(node, left);
		lq_node_append(node, right);

		left = node;
	}

	return left;
}


struct LqNode*          
lq_parse_unary_expr(struct LqContext* context)
{
	assert(context != 0);

	if(lq_parse_eat_if(context, '-' || lq_parse_eat_if(context, '~'))) {
		enum LqNodeKind kind = (lq_scanner_token(context) == '-')
			? LQ_NODE_MINUS_SIGN 
			: '~';

		struct LqNode* node = lq_node_new(lq_scanner_line(context), kind, 1);
		lq_node_append(node, lq_parse_unary_expr(context));

		return node;

	}

	lq_parse_eat_if(context, '+');

	return lq_parse_field_access_expr(context);;
}


struct LqNode*          
lq_parse_field_access_expr(struct LqContext* context)
{
	assert(context != 0);
	// TODO . operator #
	
	struct LqNode* left = lq_parse_primary_expr(context);

	while(lq_parse_eat_if(context, LQ_TOKEN_DOUBLEEXCLAMATION)) {
		struct LqNode* node = lq_node_new(lq_scanner_line(context), LQ_NODE_INDEX, 2);
		struct LqNode* right = lq_parse_primary_expr(context);

		lq_node_append(node, left);
		lq_node_append(node, right);

		left = node;
	}

	return left;
}


struct LqNode*		
lq_parse_block_expr(struct LqContext* context)
{
	assert(context != 0);

	lq_parse_eat(context,'{', "Opening Delimiter '{'  expected in this expression");

	struct LqNode* parent = lq_node_new(lq_scanner_line(context), LQ_NODE_BLOCK, 4);

	lq_parse_enter_scope(context, parent);

	while( !lq_parse_is_next(context, '}', 0) ) {
		lq_parse_eat_if(context, LQ_TOKEN_NEWLINE);

                if(lq_parse_is_next(context, LQ_TOKEN_LET, 0))
                        lq_node_append(parent, lq_parse_let_pattern_expr(context));
		else if(lq_parse_is_next_on_line(context, '=')) {
			lq_node_append(parent, lq_parse_assignment_pattern_expr(context));
		} else
                        lq_node_append(parent, lq_parse_expr(context));

	}

        lq_parse_eat(context, '}', "Closing '}' bracket missing");

	lq_parse_leave_scope(context);

	return parent;
}


struct LqNode*          
lq_parse_primary_expr(struct LqContext* context)
{
	assert(context != 0);

	if(lq_parse_is_next(context, '(', 0)) 
		return lq_parse_tuple_expr(context);
	else if(lq_parse_is_next(context, '{', 0))
		return lq_parse_block_expr(context);
	else if(lq_parse_is_next(context, '[', 0))
		return lq_parse_list_expr(context);
	else if(lq_parse_is_next(context, LQ_TOKEN_IDENTIFIER, 0) && lq_parse_is_next(context, ':', 1))
		return lq_parse_scoping_expr(context);
	else if(lq_parse_is_next(context, LQ_TOKEN_IDENTIFIER, 0) || lq_parse_is_next(context, LQ_TOKEN_EXTIDENTIFIER, 0))
		return lq_parse_valuecall_expr(context);
	else if(lq_parse_is_next(context, LQ_TOKEN_FUN, 0))
		return lq_parse_fun_expr(context);
	else if(lq_parse_is_next(context, LQ_TOKEN_IF, 0))
		return lq_parse_if_expr(context);
	else if(lq_parse_is_next(context, LQ_TOKEN_MATCH, 0))
		return lq_parse_match_expr(context);
	else if(lq_parse_eat_if(context, LQ_TOKEN_NEWLINE))
		return lq_parse_primary_expr(context);

	return lq_parse_constant_expr(context);
}


struct LqNode*          
lq_parse_if_expr(struct LqContext* context)
{ 
	assert(context != 0);

	lq_parse_eat(context, LQ_TOKEN_IF, "Missing IF keyword in this conditional expression");
	int line = lq_scanner_line(context);

	struct LqNode* node = lq_node_new(line, LQ_NODE_IF, 3);

	lq_node_append(node, lq_parse_expr(context));

	lq_parse_eat(context, LQ_TOKEN_THEN, "Failure in THEN block in this conditional expression");

	lq_node_append(node, lq_parse_expr(context));
	
	lq_parse_eat(context, LQ_TOKEN_ELSE, "Failure in ELSE block in this conditional expression");

	lq_node_append(node, lq_parse_expr(context));

	return node;
}


struct LqNode*          
lq_parse_match_expr(struct LqContext* context)
{ 
	assert(context != 0);

	lq_parse_eat(context, LQ_TOKEN_MATCH, "Missing MATCH keyword in this conditional expression");
	int line = lq_scanner_line(context);

	struct LqNode* node = lq_node_new(line, LQ_NODE_MATCH, 3);

	lq_node_append(node, lq_parse_expr(context));

	while(lq_parse_eat_if(context, LQ_TOKEN_BY)) {
		struct LqNode* by = lq_node_new(lq_scanner_line(context), LQ_NODE_BY, 2);

		lq_parse_enter_scope(context, by);

		lq_node_append(by, lq_parse_pattern_expr(context));

		lq_parse_eat(context, LQ_TOKEN_ARROWRIGHT, "Missing -> operator in match expression");
	
		lq_node_append(by, lq_parse_expr(context));

		lq_parse_leave_scope(context);

		lq_node_append(node, by);
	}

	return node;
}


struct LqNode*
lq_parse_tuple_expr(struct LqContext* context)
{
	assert(context != 0);

	struct LqNode* tuple = 0;

	lq_parse_eat(context, '(', "Delimiter '(' expected in this expression");

	int current_line = lq_scanner_line(context);

	if(lq_parse_eat_if(context, ')')) 
		return lq_node_new(current_line, LQ_NODE_TUPLE, 0);

	struct LqNode* expr = lq_parse_expr(context);

	while(lq_parse_eat_if(context, ',')) {
		if(tuple == 0) {
			tuple = lq_node_new(current_line, LQ_NODE_TUPLE, 4);
			lq_node_append(tuple, expr);
		}

		lq_node_append(tuple, lq_parse_expr(context));
	}

	lq_parse_eat(context, ')', "Delimiter ')' expected in this expression");

	return (tuple == 0) ? expr : tuple;
}


struct LqNode*          
lq_parse_scoping_expr(struct LqContext* context)
{
	assert(context != 0);

	struct LqNode* namespace = 0;

	while(lq_parse_is_next(context, LQ_TOKEN_IDENTIFIER, 0) && lq_parse_is_next(context, ':', 1)) {
		struct LqToken identifier = lq_parse_next(context);
		struct LqNode* name = lq_node_identifier_new(identifier.line, identifier.text);

		if(namespace == 0) {
			namespace = lq_node_new(identifier.line, ':', 2);
			lq_node_append(namespace, name);
		} else {
			struct LqNode* parent = lq_node_new(identifier.line, ':', 2);
		
			lq_node_append(namespace, name);
			lq_node_append(parent, namespace);
			namespace = parent;
		}

		lq_parse_eat(context, ':', "Missing namespace ':' seperator in this value call");
	}

	if(namespace != 0)
		lq_node_append(namespace, lq_parse_valuecall_expr(context));
	else
		return lq_parse_valuecall_expr(context);

	return namespace;
}


int		
lq_parse_is_next_expr(struct LqContext* context)
{
	assert(context != 0);

	struct LqToken next = lq_scanner_peek(context, 0);

	return (next.value == '[' 
			|| next.value == '(' 
			|| next.value == LQ_TOKEN_IDENTIFIER 
			|| next.value == LQ_TOKEN_EXTIDENTIFIER
			|| next.value == LQ_TOKEN_DECNUMBER 
			|| next.value == LQ_TOKEN_BINNUMBER 
			|| next.value == LQ_TOKEN_OCTNUMBER 
			|| next.value == LQ_TOKEN_HEXNUMBER
			|| next.value == LQ_TOKEN_FLOATPOINT
			|| next.value == LQ_TOKEN_STRING
			|| next.value == LQ_TOKEN_RAWSTRING
			|| next.value == LQ_TOKEN_ATOM
			|| next.value == LQ_TOKEN_CHARACTER
			|| next.value == LQ_TOKEN_FUN
			|| next.value == '~');
}


struct LqNode*          
lq_parse_valuecall_expr(struct LqContext* context)
{
	assert(context != 0);

	struct LqToken constant = lq_parse_next(context);

	struct LqNode* value = lq_node_value_new(constant.line, constant.text);

	while(lq_parse_is_next_expr(context)) {
		if(lq_node_children(value) > 1) {
			struct LqNode* parent = lq_node_new(constant.line, LQ_NODE_VALUE, 2);
			lq_node_append(parent, value);
			value = parent;
		}

		if(lq_parse_is_next(context, LQ_TOKEN_IDENTIFIER, 0) || lq_parse_is_next(context, LQ_TOKEN_EXTIDENTIFIER, 0)) {
			constant = lq_parse_next(context);
			lq_node_append(value, lq_node_value_new(constant.line, constant.text));
		} else {
			lq_node_append(value, lq_parse_expr(context));
		}
	}

	return value;
}


struct LqNode*		
lq_parse_list_expr(struct LqContext* context)
{
	assert(context != 0);

	lq_parse_eat(context, '[', "List opening bracket '[' missing in this expression");
	int current_line = lq_scanner_line(context);
	struct LqNode* list = lq_node_new(current_line, LQ_NODE_LIST, 4);

	if(lq_parse_eat_if(context, ']'))
		return list;

	struct LqNode* expr = lq_parse_expr(context);

	lq_node_append(list, expr);

	if(lq_parse_eat_if(context, '|')) {
		lq_node_append(list, lq_parse_list_generator_expr(context));

		while(lq_parse_eat_if(context, ','))
			lq_node_append(list, lq_parse_list_generator_expr(context));
	} else {
		while(lq_parse_eat_if(context, ','))
			lq_node_append(list, lq_parse_expr(context));
	}

	lq_parse_eat(context, ']', "List closing bracket ']' missing in this expression");

	return list;
}


struct LqNode*		
lq_parse_list_generator_expr(struct LqContext* context)
{
	assert(context != 0);

	struct LqNode* generator = lq_node_new(lq_scanner_line(context), LQ_NODE_LIST_GENERATOR, 2);
	struct LqNode* pattern = lq_parse_expr(context);

	lq_parse_eat(context, LQ_TOKEN_ARROWLEFT, "Generator symbol <- is missing in list expression");

	struct LqNode* expr = lq_parse_expr(context);

	lq_node_append(generator, pattern);
	lq_node_append(generator, expr);

	return generator;
}


struct LqNode*
lq_parse_fun_expr(struct LqContext* context)
{
	assert(context != 0);
	
	lq_parse_eat(context, LQ_TOKEN_FUN, "fun operator is missing in this expression");

	struct LqNode* fun = lq_node_new(lq_scanner_line(context), LQ_NODE_FUN, 1);

	do {
		struct LqNode* by = lq_node_new(lq_scanner_line(context), LQ_NODE_BY, 2);

		lq_parse_enter_scope(context, by);
		
		struct LqNode* pexpr = lq_parse_pattern_expr(context);

		lq_parse_eat(context, LQ_TOKEN_ARROWRIGHT, "Missing -> operator in fun expression");
	
		lq_node_append(by, pexpr);
		lq_node_append(by, lq_parse_expr(context));
		lq_node_append(fun, by);

		lq_parse_leave_scope(context);

	} while(lq_parse_eat_if(context, ','));

	return fun;
}

struct LqNode*          
lq_parse_constant_expr(struct LqContext* context)
{
	assert(context != 0);

	struct LqToken constant = lq_parse_next(context);

	switch(constant.value) {
		case LQ_TOKEN_DECNUMBER:
			return lq_node_integer_new(constant.line, constant.text, 10);
		case LQ_TOKEN_BINNUMBER:
			return lq_node_integer_new(constant.line, constant.text, 2);
		case LQ_TOKEN_OCTNUMBER:
			return lq_node_integer_new(constant.line, constant.text, 8);
		case LQ_TOKEN_HEXNUMBER:
			return lq_node_integer_new(constant.line, constant.text, 16);
		case LQ_TOKEN_FLOATPOINT:
			return lq_node_floatpoint_new(constant.line, constant.text);
		case LQ_TOKEN_CHARACTER:
			return lq_node_character_new(constant.line, constant.text);
		case LQ_TOKEN_STRING:
			return lq_node_string_new(constant.line, constant.text, FALSE);
		case LQ_TOKEN_RAWSTRING:
			return lq_node_string_new(constant.line, constant.text, TRUE);
		case LQ_TOKEN_ATOM:
			return lq_node_atom_new(constant.line, constant.text);
		default:
			lq_error_at_line(context->file, constant.line, "No valid expression could be selected with current token %s", 
					lq_tok_to_string(constant.value));
			assert(0);
			return lq_parse_constant_expr(context);
	}

	return 0;
}

int		
lq_parse_is_next_pattern(struct LqContext* context)
{
	assert(context != 0);

	struct LqToken next = lq_scanner_peek(context, 0);

	return (next.value == '[' 
			|| next.value == '(' 
			|| next.value == LQ_TOKEN_IDENTIFIER 
			|| next.value == LQ_TOKEN_EXTIDENTIFIER
			|| next.value == LQ_TOKEN_DECNUMBER 
			|| next.value == LQ_TOKEN_BINNUMBER 
			|| next.value == LQ_TOKEN_OCTNUMBER 
			|| next.value == LQ_TOKEN_HEXNUMBER
			|| next.value == LQ_TOKEN_FLOATPOINT
			|| next.value == LQ_TOKEN_STRING
			|| next.value == LQ_TOKEN_RAWSTRING
			|| next.value == LQ_TOKEN_CHARACTER
			|| next.value == LQ_TOKEN_ATOM
			|| next.value == LQ_TOKEN_UNDERSCORE
			|| next.value == '~'
			|| next.value == '-');
}


struct LqNode*		
lq_parse_pattern_expr(struct LqContext* context)
{
	assert(context != 0);

	struct LqNode* pattern = lq_node_new(lq_scanner_line(context), LQ_NODE_PATTERN, 2);

	while(lq_parse_is_next_pattern(context)) {
		lq_node_append(pattern, lq_parse_cons_pattern_expr(context));
	}

	return pattern;
}


struct LqNode*
lq_parse_tuple_pattern_expr(struct LqContext* context)
{
	assert(context != 0);

	lq_parse_eat(context, '(', "Tuple delimiter '(' expected in this pattern");
	
	int line = lq_scanner_line(context);
	struct LqNode* tuple = 0;

	if(lq_parse_eat_if(context, ')')) 
		return lq_node_new(line, LQ_NODE_TUPLE, 0);

	struct LqNode* pattern = lq_parse_cons_pattern_expr(context);

	while(lq_parse_eat_if(context, ',')) {
		if(tuple == 0) {
			tuple = lq_node_new(line, LQ_NODE_TUPLE, 4);
			lq_node_append(tuple, pattern);
		}

		lq_node_append(tuple, lq_parse_cons_pattern_expr(context));
	}

	lq_parse_eat(context, ')', "Tuple delimiter ')' expected in this pattern");

	return (tuple == 0) ? pattern : tuple;

}


struct LqNode*
lq_parse_list_pattern_expr(struct LqContext* context)
{
	assert(context != 0);

	lq_parse_eat(context, '[', "List opening bracket '[' missing in this pattern");

	int line = lq_scanner_line(context);
	struct LqNode* list = lq_node_new(line, LQ_NODE_LIST, 4);

	if(lq_parse_eat_if(context, ']'))
		return list;

	do {
		struct LqNode* pattern = lq_parse_cons_pattern_expr(context);
		lq_node_append(list, pattern);
	} while(lq_parse_eat_if(context, ','));


	lq_parse_eat(context, ']', "List closing bracket ']' missing in this pattern");

	return list;
}


struct LqNode*
lq_parse_cons_pattern_expr(struct LqContext* context)
{
	assert(context != 0);

	struct LqNode* left = lq_parse_base_pattern_expr(context);

	if(lq_parse_eat_if(context, LQ_TOKEN_DOUBLECOLON)) {
		struct LqNode* node = lq_node_new(lq_scanner_line(context), LQ_NODE_CONS, 2);
		struct LqNode* right = lq_parse_cons_pattern_expr(context);

		lq_node_append(node, left);
		lq_node_append(node, right);

		left = node;
	}

	return left;
}


struct LqNode*
lq_parse_base_pattern_expr(struct LqContext* context) {
	assert(context != 0);

	if(lq_parse_is_next(context, '(', 0)) {
		return lq_parse_tuple_pattern_expr(context);
	} else if(lq_parse_is_next(context, '[', 0))
		return lq_parse_list_pattern_expr(context);

	return lq_parse_constant_pattern_expr(context);
}


struct LqNode*          
lq_parse_constant_pattern_expr(struct LqContext* context)
{
	assert(context != 0);

	struct LqToken constant = lq_parse_next(context);

	switch(constant.value) {
		case LQ_TOKEN_DECNUMBER:
			return lq_node_integer_new(constant.line, constant.text, 10);
		case LQ_TOKEN_BINNUMBER:
			return lq_node_integer_new(constant.line, constant.text, 2);
		case LQ_TOKEN_OCTNUMBER:
			return lq_node_integer_new(constant.line, constant.text, 8);
		case LQ_TOKEN_HEXNUMBER:
			return lq_node_integer_new(constant.line, constant.text, 16);
		case LQ_TOKEN_FLOATPOINT:
			return lq_node_floatpoint_new(constant.line, constant.text);
		case LQ_TOKEN_CHARACTER:
			return lq_node_character_new(constant.line, constant.text);
		case LQ_TOKEN_STRING:
			return lq_node_string_new(constant.line, constant.text, FALSE);
		case LQ_TOKEN_RAWSTRING:
			return lq_node_string_new(constant.line, constant.text, TRUE);
		case LQ_TOKEN_ATOM:
			return lq_node_atom_new(constant.line, constant.text);
		case LQ_TOKEN_IDENTIFIER:
		case LQ_TOKEN_EXTIDENTIFIER:
			{
				struct LqNode* node = lq_node_identifier_new(constant.line, constant.text);
				struct LqSymbol* sym = lq_symbol_value_new(constant.line, node);

				if(lq_symboltable_add(context, constant.text, sym) == FALSE) {
					lq_error_at_line(context->file, constant.line, "Conflicting value declaration. %s has already been set in this scope.", 
							constant.text);
					free(sym);
				}

				return node;
			}
		case LQ_TOKEN_UNDERSCORE:
			return lq_node_new(constant.line, LQ_NODE_UNDERSCORE, 0);
		default:
			lq_error_at_line(context->file, constant.line, "No valid pattern could be selected with current token %s", 
					lq_tok_to_string(constant.value));
			return lq_parse_constant_pattern_expr(context);
	}

	return 0;
}



